package com.xms.form.api.controller;

import com.xms.core.enums.AccessRightValue;
import com.xms.core.enums.EntityPermissionDepth;
import com.xms.core.exception.XmsUnauthorizedException;
import com.xms.form.api.model.FormAllDataModel;
import com.xms.form.core.FormMetaDescriptor;
import com.xms.form.core.FormState;
import com.xms.form.entity.SystemForm;
import com.xms.form.service.IFormBuilderService;
import com.xms.form.service.ISystemFormFinderService;
import com.xms.form.service.ISystemFormUpdaterService;
import com.xms.ribbonbutton.core.RibbonButtonArea;
import com.xms.ribbonbutton.entity.RibbonButton;
import com.xms.ribbonbutton.service.IRibbonButtonFinderService;
import com.xms.ribbonbutton.service.IRibbonButtonStatusSetter;
import com.xms.schema.core.AttributeDefaults;
import com.xms.schema.entity.Attribute;
import com.xms.schema.entity.Entity;
import com.xms.schema.extension.AttributeExt;
import com.xms.schema.service.attribute.IAttributeFinderService;
import com.xms.schema.service.entity.IEntityFinderService;
import com.xms.sdk.service.IDataFinder;
import com.xms.security.entity.RoleEntityPermission;
import com.xms.security.service.dataauth.IRoleEntityPermissionService;
import com.xms.security.service.principal.ISystemUserPermissionService;
import com.xms.utils.CollectionUtil;
import com.xms.utils.JsonUtil;
import com.xms.utils.StringUtil;
import com.xms.utils.UUIDUtil;
import com.xms.web.framework.controller.ApiBaseController;
import com.xms.web.framework.model.JsonResultObject;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * <p>
 * EntityFormController
 * </p>
 *
 * @author migo
 * @since 2021/9/13
 */
@RestController
@RequestMapping("{org}/api/schema/form")
public class EntityFormController extends ApiBaseController {
    private IEntityFinderService _entityFinderService;
    private ISystemFormFinderService _systemFormFinderService;
    private IRibbonButtonFinderService _ribbonButtonFinderService;
    private IDataFinder _dataFinder;
    private IAttributeFinderService _attributeFinderService;
    private ISystemUserPermissionService _systemUserPermissionService;
    private IFormBuilderService _formService;
    private IRibbonButtonStatusSetter _ribbonButtonStatusSetter;
    private IRoleEntityPermissionService _roleEntityPermissionService;

    @Autowired
    public EntityFormController(ISystemFormFinderService systemFormFinderService
            , ISystemFormUpdaterService systemFormUpdaterService
            , IEntityFinderService entityFinderService
            , IRibbonButtonFinderService ribbonButtonFinderService
            , IDataFinder dataFinder
            , IAttributeFinderService attributeFinderService
            , ISystemUserPermissionService systemUserPermissionService
            , IFormBuilderService formService
            , IRibbonButtonStatusSetter ribbonButtonStatusSetter
            , IRoleEntityPermissionService roleEntityPermissionService) {
        _systemFormFinderService = systemFormFinderService;
        _entityFinderService = entityFinderService;
        _ribbonButtonFinderService = ribbonButtonFinderService;
        _dataFinder = dataFinder;
        _attributeFinderService = attributeFinderService;
        _systemUserPermissionService = systemUserPermissionService;
        _formService = formService;
        _ribbonButtonStatusSetter = ribbonButtonStatusSetter;
        _roleEntityPermissionService = roleEntityPermissionService;
    }

    @ApiOperation("查询表单所有数据")
    @GetMapping("getall")
    public JsonResultObject getAllData(@RequestParam(value = "entityid", required = false) UUID entityId,
                                       @RequestParam(value = "entityname", required = false) String entityName,
                                       @RequestParam(value = "formid", required = false) UUID formId,
                                       @RequestParam(value = "recordid", required = false) UUID recordId,
                                       @RequestParam(value = "relationshipname", required = false) String relationShipName,
                                       @RequestParam(value = "referencedrecordid", required = false) UUID referencedRecordId,
                                       @RequestParam(value = "copyid", required = false) UUID copyId) throws Exception {
        FormAllDataModel result = new FormAllDataModel();
        if (UUIDUtil.isEmpty(entityId) && StringUtil.isEmpty(entityName)) {
            return JNotFound();
        }
        entityName = entityName.toLowerCase();
        Entity entity = UUIDUtil.isEmpty(entityId) ? _entityFinderService.getByName(entityName) : _entityFinderService.getById(entityId);
        if (entity == null) {
            return JNotFound();
        }
        result.EntityId = entity.getEntityid();
        result.EntityName = entity.getName();
        result.EntityMetaData = entity;
        result.RelationShipName = StringUtil.notEmpty(relationShipName) ? relationShipName.toLowerCase() : "";
        result.ReferencedRecordId = referencedRecordId;
        result.FormId = formId;
        result.WorkFlowProcessState = 0;

        if (UUIDUtil.notEmpty(recordId)) {
            List<Attribute> attributes = _attributeFinderService.getByEntityId(entity.getEntityid());
            com.xms.core.data.Entity record = _dataFinder.retrieveById(entity.getName(), recordId,
                    attributes.stream().filter(x -> AttributeExt.typeIsPrimaryKey(x)).findFirst().get().getName());
            if (CollectionUtil.isEmpty(record)) {
                return JNotFound();
            }
            if (attributes.stream().anyMatch(n -> StringUtil.equalSafe(n.getDataformat(), "fileupload"))) {
                List<Attribute> fileAttributes = attributes.stream().filter(n -> StringUtil.equalSafe(n.getDataformat(), "fileupload")).collect(Collectors.toList());
                for (Attribute item : fileAttributes) {
                    if (StringUtil.notEmpty(record.getStringValue(item.getName()))) {
                        record.setValue(item.getName(), "");
                    } else {
                        record.remove(item.getName());
                    }
                }
            }
            result.Entity = record;
            result.RecordId = recordId;
            result.FormState = FormState.Update;
            if (result.Entity.getBoolValue("statecode") == false) {
                result.FormState = FormState.Disabled;
                //model.ReadOnly = true;
            }
        } else if (UUIDUtil.notEmpty(copyId)) {
            List<Attribute> attributes = _attributeFinderService.getByEntityId(entity.getEntityid());
            com.xms.core.data.Entity record = _dataFinder.retrieveById(entity.getName(), copyId,
                    attributes.stream().filter(x -> AttributeExt.typeIsPrimaryKey(x)).findFirst().get().getName());
            if (CollectionUtil.isEmpty(record)) {
                return JNotFound();
            }
            if (attributes.stream().anyMatch(n -> n.getDataformat().equalsIgnoreCase("fileupload"))) {
                List<Attribute> fileAttributes = attributes.stream().filter(n -> n.getDataformat().equalsIgnoreCase("fileupload")).collect(Collectors.toList());
                for (Attribute item : fileAttributes) {
                    if (StringUtil.notEmpty(record.getStringValue(item.getName()))) {
                        record.setValue(item.getName(), "");
                    } else {
                        record.remove(item.getName());
                    }
                }
            }
            record.removeItems(AttributeDefaults.SYSTEM_ATTRIBUTES);
            result.Entity = record;
            //m.RecordId = model.RecordId;
            result.FormState = FormState.Create;
        } else {
            result.FormState = FormState.Create;
        }
        //result.ReadOnly = args.ReadOnly;
        boolean isCreate = UUIDUtil.isEmpty(recordId);
        boolean isFlowing = false;
        SystemForm formEntity = null;
        if (formEntity == null) {
            if (UUIDUtil.notEmpty(result.FormId)) {
                formEntity = _systemFormFinderService.getById(result.FormId);
                if (formEntity != null && !formEntity.getStatecode()) {
                    formEntity = null;//表单已禁用
                }
            } else {
                //获取实体默认表单
                formEntity = _systemFormFinderService.getDefaultForm(result.EntityId);
            }
        }
        if (formEntity == null) {
            return JError("没有找到可用表单");
        }
        result.HasBasePermission = true;
        List<RoleEntityPermission> entityPermissions = _roleEntityPermissionService.getUserPermissions(result.EntityMetaData.getName(), _currentUser.getUser().SystemUserId);
        //如果非流程环节，则检查实体的读取权限
        if (!isFlowing) {
            if (result.EntityMetaData.getAuthorizationenabled() && !_currentUser.isAdministrator()) {
                RoleEntityPermission readPermission = entityPermissions.stream().filter(x -> x.getAccessRight() == AccessRightValue.Read.value()).findFirst().orElse(null);
                boolean hasPermission = readPermission != null && readPermission.getAccessRightsMask() != EntityPermissionDepth.None;
                if (!hasPermission) {
                    //直接趴窝
                    throw new XmsUnauthorizedException(String.format("没有 '%s' 的 '读取' 权限", result.EntityMetaData.getLocalizedname()));
                }
                //实体的创建或更新权限
                RoleEntityPermission rep = entityPermissions.stream().filter(x -> x.getAccessRight() == (isCreate ? AccessRightValue.Create.value() : AccessRightValue.Update.value())).findFirst().orElse(null);
                result.HasBasePermission = rep != null && rep.getAccessRightsMask() != EntityPermissionDepth.None;
            }
        }

        result.FormInfo = formEntity;
        result.FormId = formEntity.getSystemformid();
        FormMetaDescriptor formMetaDescriptor = _formService.build(formEntity);
        result.Form = formMetaDescriptor.form;
        //表单可用状态
        /*FormBuilder formBuilder = new FormBuilder(formEntity.getFormconfig());
        if (!isCreate && result.FormState != FormState.Disabled && formBuilder.Form.FormRules.NotEmpty())
        {
            if (_systemFormStatusSetter.IsDisabled(formBuilder.Form.FormRules, m.Entity))
            {
                m.FormState = FormState.Disabled;
            }
        }*/
        //获取所有字段信息
        result.AttributeList = formMetaDescriptor.attributes;
        //获取字段权限
        if (!_currentUser.isAdministrator() && result.AttributeList.stream().anyMatch(n -> n.getAuthorizationenabled())) {
            List<UUID> securityFields = result.AttributeList.stream().filter(n -> n.getAuthorizationenabled()).map(Attribute::getAttributeid).collect(Collectors.toList());
            if (CollectionUtil.notEmpty(securityFields)) {
                //无权限的字段
                List<UUID> noneRead = _systemUserPermissionService.getNoneReadFields(_currentUser.getUser().SystemUserId, securityFields);
                List<UUID> noneEdit = _systemUserPermissionService.getNoneEditFields(_currentUser.getUser().SystemUserId, securityFields);
                //移除无读取权限的字段内容
                if (CollectionUtil.notEmpty(result.Entity)) {
                    List<String> keys = result.AttributeList.stream().filter(x -> noneRead.contains(x.getAttributeid())).map(Attribute::getName).collect(Collectors.toList());
                    result.Entity.removeItems(keys);
                }
                result.NoneReadFields = noneRead;
                result.NoneEditFields = noneEdit;
            }
        }
        //buttons
        List<RibbonButton> buttons = _ribbonButtonFinderService.getByArea(result.EntityId, RibbonButtonArea.Form);
        if (CollectionUtil.notEmpty(buttons) && formEntity.getIscustombutton() && StringUtil.notEmpty(formEntity.getCustombuttons())) {
            List<UUID> buttonid = JsonUtil.toList(formEntity.getCustombuttons(), UUID.class);
            buttons.removeIf(x -> !buttonid.contains(x.getRibbonbuttonid()));
        }
        if (CollectionUtil.notEmpty(buttons)) {
            //buttons = buttons.sort(x->x.getDisplayorder());
            buttons.removeIf(x -> x.getStatecode() == false);
            result.RibbonButtons = buttons;
            _ribbonButtonStatusSetter.set(result.RibbonButtons, result.FormState, result.Entity);
        }
        //webresource
        List<String> jsLibs = new ArrayList<>();
        List<UUID> resources = new ArrayList<>();
        if (CollectionUtil.notEmpty(result.RibbonButtons)) {
            for (RibbonButton btn : result.RibbonButtons) {
                if (StringUtil.notEmpty(btn.getJslibrary())) {
                    if (StringUtil.startsWithIgnoreCase(btn.getJslibrary(), "ws:")) {
                        resources.add(UUID.fromString(btn.getJslibrary().replace("ws:", "")));
                    } else if (!jsLibs.contains(btn.getJslibrary())) {
                        jsLibs.add(btn.getJslibrary());
                    }
                }
            }
        }
        if (CollectionUtil.notEmpty(result.Form.ClientResources)) {
            for (String item : result.Form.ClientResources) {
                if (StringUtil.startsWithIgnoreCase(item, "ws:")) {
                    resources.add(UUID.fromString(item.replace("ws:", "")));
                } else {
                    resources.add(UUID.fromString(item));
                }
            }
        }
        result.WebResources = StringUtil.join(resources.stream().distinct().collect(Collectors.toList()), ",", "");
        /*result.SnRule = _serialNumberRuleFinder.FindByEntityId(args.EntityId);
        if (m.SnRule != null && m.Entity.NotEmpty() && args.CopyId.HasValue)
        {
            m.Entity.SetAttributeValue(m.SnRule.AttributeName, null);
        }
        result.StageId = args.StageId;
        result.BusinessFlowId = args.BusinessFlowId;
        result.BusinessFlowInstanceId = args.BusinessFlowInstanceId;*/
        return JOk(result);
    }
}
